Skip to content

Comments

fix: exclude DiffSource interface field from JSON serialization (#305)#309

Merged
tianzhou merged 1 commit intomainfrom
fix/issue-305-debug-json-deserialization
Feb 22, 2026
Merged

fix: exclude DiffSource interface field from JSON serialization (#305)#309
tianzhou merged 1 commit intomainfrom
fix/issue-305-debug-json-deserialization

Conversation

@tianzhou
Copy link
Contributor

Summary

  • Plans generated with --debug included the Diff.Source field (a DiffSource interface) in JSON output. Go's json.Unmarshal cannot reconstruct interface types, causing FromJSON() to fail when applying debug plans via pgschema apply --plan plan.json.
  • Changed the JSON tag on Diff.Source from json:"source,omitempty" to json:"-" to exclude it from serialization. All in-memory usage (rewrite logic, display formatting) is unaffected.

Fixes #305

Test plan

  • New test TestPlanDebugJSONRoundTrip verifies debug JSON round-trip: serialize with ToJSONWithDebug(true) then deserialize with FromJSON()
  • Run: go test -v ./internal/plan -run TestPlanDebugJSONRoundTrip
  • All existing plan tests pass: go test -v ./internal/plan
  • Full CI suite passes

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings February 22, 2026 03:38
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes debug-mode plan JSON round-tripping by preventing an interface-typed field (diff.Diff.Source / DiffSource) from being serialized, which previously made plan.FromJSON() fail when applying --debug plans.

Changes:

  • Exclude diff.Diff.Source from JSON serialization/deserialization via json:"-".
  • Add a regression test that serializes a debug plan with ToJSONWithDebug(true) and verifies FromJSON() can load it successfully.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
internal/diff/diff.go Stops serializing the interface-typed Diff.Source field to keep debug JSON loadable.
internal/plan/plan_test.go Adds a debug JSON round-trip test covering issue #305.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Operation DiffOperation `json:"operation"` // create, alter, drop, replace
Path string `json:"path"`
Source DiffSource `json:"source,omitempty"`
Source DiffSource `json:"-"`
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diff.Source is now excluded from JSON, but the code doesn’t explain why. Consider adding a short inline comment on this field noting that it’s an interface (DiffSource) and is intentionally not serializable/deserializable (issue #305), to reduce the chance of an accidental revert later.

Suggested change
Source DiffSource `json:"-"`
Source DiffSource `json:"-"` // interface field; intentionally not JSON-serializable/deserializable (see issue #305)

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added inline comment: // interface; not JSON-serializable (see #305)

Comment on lines +294 to +298
loaded, err := FromJSON([]byte(debugJSON))
if err != nil {
t.Fatalf("Failed to deserialize debug plan JSON: %v", err)
}

Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: consider asserting that debug mode actually emitted source_diffs (e.g., len(loaded.SourceDiffs) > 0). It makes the test more robust by ensuring ToJSONWithDebug(true) continues to include debug diffs, rather than the test passing if that output changes later.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added len(loaded.SourceDiffs) == 0 assertion to verify debug mode actually emits SourceDiffs.


p := NewPlan(diffs)

// Serialize with debug mode (includes SourceDiffs with Source interface fields)
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says debug serialization "includes SourceDiffs with Source interface fields", but with Diff.Source tagged json:"-" the Source field won’t be present in the JSON anymore. Updating the comment to reflect the new behavior will prevent confusion when debugging future failures.

Suggested change
// Serialize with debug mode (includes SourceDiffs with Source interface fields)
// Serialize with debug mode (includes additional debug metadata but omits Diff.Source interface fields)

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Comment now reads: // includes SourceDiffs; Diff.Source is excluded via json:"-"

@greptile-apps
Copy link

greptile-apps bot commented Feb 22, 2026

Greptile Summary

Fixed JSON serialization issue where --debug plans couldn't be deserialized by FromJSON(). The Diff.Source field (a DiffSource interface) is now excluded from JSON output via json:"-" tag, since Go's json.Unmarshal cannot reconstruct interface types. This field is only used in-memory for rewrite logic and display formatting, not needed for plan persistence.

Key Changes:

  • Changed Diff.Source JSON tag to exclude field from serialization
  • Added comprehensive test verifying debug JSON round-trip works correctly
  • All in-memory usage patterns (rewrite logic in plan/rewrite.go, display formatting) remain unaffected since they operate on freshly-generated plans before serialization

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The fix is minimal, well-targeted, and addresses the root cause directly. The Source field is only used in-memory during plan generation (rewrite logic and display), never after JSON deserialization. The comprehensive test verifies the fix works and prevents regression. All existing usages of Source field are in plan generation code paths, not in the apply-from-JSON code path.
  • No files require special attention

Important Files Changed

Filename Overview
internal/diff/diff.go Changed Source field JSON tag from json:"source,omitempty" to json:"-" to exclude it from serialization, fixing JSON round-trip issue
internal/plan/plan_test.go Added comprehensive test TestPlanDebugJSONRoundTrip verifying debug JSON serialization/deserialization and round-trip stability

Last reviewed commit: 76db096

Plans generated with --debug included the Diff.Source field (a DiffSource
interface) in JSON output. Go's json.Unmarshal cannot reconstruct interface
types, causing FromJSON() to fail when applying debug plans.

Change the JSON tag from `json:"source,omitempty"` to `json:"-"` to exclude
Source from serialization. All in-memory usage (rewrite, formatting, display)
is unaffected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tianzhou tianzhou force-pushed the fix/issue-305-debug-json-deserialization branch from 76db096 to 6c6fb5d Compare February 22, 2026 03:43
@tianzhou tianzhou merged commit 2cfa5e5 into main Feb 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: DiffSource interface field on Diff breaks JSON deserialization in debug mode

1 participant